import React from 'react';
import pluralize from 'pluralize';
import reduce from 'lodash/reduce';

import entityTypes from 'constants/entityTypes';
import { severities } from 'constants/severities';
import entityLabels from 'messages/entity';
import { getDateTime } from 'utils/dateUtils';

export function getSeverityByCvss(cvss) {
    if (cvss < 4.0) {
        return severities.LOW_SEVERITY;
    }
    if (cvss < 7.0) {
        return severities.MEDIUM_SEVERITY;
    }
    if (cvss < 9.0) {
        return severities.HIGH_SEVERITY;
    }
    return severities.CRITICAL_SEVERITY;
}

export function getSeverityCounts(vulnerabilities = []) {
    const initialCounts = {
        [severities.CRITICAL_SEVERITY]: {
            total: 0,
            fixable: 0,
        },
        [severities.HIGH_SEVERITY]: {
            total: 0,
            fixable: 0,
        },
        [severities.MEDIUM_SEVERITY]: {
            total: 0,
            fixable: 0,
        },
        [severities.LOW_SEVERITY]: {
            total: 0,
            fixable: 0,
        },
    };

    return vulnerabilities.reduce((acc, vuln) => {
        const severity = getSeverityByCvss(vuln.cvss);
        const fixable = vuln.isFixable;

        const updatedCounts = {
            total: acc[severity].total + 1,
            fixable: fixable ? acc[severity].fixable + 1 : acc[severity].fixable,
        };

        return { ...acc, [severity]: updatedCounts };
    }, initialCounts);
}

export function getTooltip(vuln) {
    const {
        cve,
        cvss,
        scoreVersion,
        createdAt,
        lastScanned,
        deploymentCount,
        imageCount,
        summary,
    } = vuln;
    const titleDate = lastScanned || createdAt;
    const tooltipTitle = titleDate ? getDateTime(titleDate) : 'N/A';
    const tooltipBody = (
        <ul className="flex-1 border-base-300 overflow-hidden">
            <li className="py-1 flex flex-col">
                <span className="font-700 mr-2">CVE:</span>
                <span>{cve}</span>
            </li>
            <li className="py-1 flex flex-col">
                <span className="font-700 mr-2">CVSS:</span>
                <span>{Math.round(cvss * 100) / 100}</span>
            </li>
            <li className="py-1 flex flex-col">
                <span className="font-700 mr-2">Description:</span>
                <span>{summary}</span>
            </li>
            <li className="py-1 flex flex-col">
                <span className="font-700 mr-2">Impact:</span>
                <span>{`${deploymentCount} ${pluralize(
                    'deployment',
                    deploymentCount
                )}, ${imageCount} ${pluralize('images', imageCount)}`}</span>
            </li>
        </ul>
    );
    const tooltipFooter = `Scored using CVSS ${scoreVersion}`;

    return {
        title: tooltipTitle,
        body: tooltipBody,
        footer: tooltipFooter,
    };
}

// TODO: not sure if we need the cveType parameter, but put it in to allow for flexibility for other widgets
export function getVulnerabilityChips(workflowState, vulnerabilities, cveType = entityTypes.CVE) {
    return vulnerabilities.map((vuln) => {
        const { id, cve, cvss, scoreVersion, imageCount, envImpact, isFixable } = vuln;

        const text = cve;
        const envImpactPercentage = `${(envImpact * 100).toFixed(0)}%`;
        const tooltip = getTooltip(vuln);

        return {
            text,
            subText: `/ CVSS: ${cvss.toFixed(1)} (${scoreVersion})`,
            url: workflowState.pushRelatedEntity(cveType, id).toUrl(),
            // @TODO: remove JSX generation from processing data and into Numbered List function
            //   for example,
            //     just create an array of optional objects here,
            //     which would drive chip-creation in the JSX of the numbered list
            component: (
                <>
                    {imageCount > 0 && (
                        <div className="ml-4 text-base-600 text-sm">
                            {`${imageCount} ${pluralize(
                                entityLabels[entityTypes.IMAGE],
                                imageCount
                            )}`}
                        </div>
                    )}
                    {!!envImpact && (
                        <div className="ml-4 text-base-600 text-sm">{`Env Impact: ${envImpactPercentage}`}</div>
                    )}
                    {isFixable && <div className="ml-4 text-base-600 text-sm">Fixable</div>}
                </>
            ),
            tooltip,
        };
    });
}

export function parseCVESearch(searchState) {
    const parsedSearch = reduce(
        searchState,
        (result, value, key) => {
            let newKey = key;
            let newValue = value;

            // replace any permutation of '(F|f)ixable: true' with  'Fixed By: "r/.*"'
            if ((key.includes('Fixable') || key.includes('fixable')) && value === 'true') {
                newKey = 'Fixed By';
                newValue = 'r/.*';
            }

            return { ...result, [newKey]: newValue };
        },
        {}
    );
    return parsedSearch;
}

export function splitCvesByType(cves = []) {
    return cves.reduce(
        (acc, cve) => {
            // TODO: remove this whole function and the logic that calls it after RocksDB no longer supported
            if (!cve.vulnerabilityTypes) {
                return acc;
            }
            if (cve.vulnerabilityTypes.includes('IMAGE_CVE')) {
                acc.IMAGE_CVE.push(cve);
            }
            if (cve.vulnerabilityTypes.includes('NODE_CVE')) {
                acc.NODE_CVE.push(cve);
            }
            if (cve.vulnerabilityTypes.includes('K8S_CVE')) {
                acc.K8S_CVE.push(cve);
            }
            if (cve.vulnerabilityTypes.includes('OPENSHIFT_CVE')) {
                acc.OPENSHIFT_CVE.push(cve);
            }

            return acc;
        },
        { IMAGE_CVE: [], NODE_CVE: [], K8S_CVE: [], OPENSHIFT_CVE: [] }
    );
}

export default {
    getSeverityByCvss,
    getVulnerabilityChips,
    parseCVESearch,
    splitCvesByType,
};
